import 'dart:core';

import 'package:ideology/shared/widgets/code_input/highlight/token.dart';

/// 词法分析的状态机状态。
///
/// - [normal]：普通扫描模式；
/// - [blockComment]：位于多行注释 `/* ... */` 内；
/// - [stringSingle]：位于单引号字符串 `'...'` 内；
/// - [stringDouble]：位于双引号字符串 `"..."` 内。
///
/// 之所以需要状态，是因为多行注释和字符串可能跨行，
/// 需要记住进入状态，下一行继续解析。
enum LexState {
  normal,
  blockComment,     // inside /* ... */
  stringSingle,     // inside '...'
  stringDouble,     // inside "..."
}

/// **正则/规则驱动的无状态 Lexer**（逐行处理）。
///
/// - 负责将一行源码字符串切分为 [Token] 列表；
/// - 会根据 [LexState] 记录输入/输出状态，以便处理跨行的注释/字符串；
/// - 识别的 token 类型包括：
///   - 关键字 ([keywords] 提供集合)
///   - 标识符
///   - 数字字面量
///   - 字符串（带转义支持）
///   - 单行注释 `//` 或 `#`
///   - 多行注释 `/* ... */`
///   - 操作符 / 标点符号
///   - 空白字符
///   - 其他未分类符号
class RegexLexer {
  /// 关键字集合，由调用方提供。
  final Set<String> keywords;

  RegexLexer({required this.keywords});

  /// 将一行源码进行词法分析。
  ///
  /// - [line]：输入的一行代码文本；
  /// - [inState]：进入行时的 lexer 状态；
  ///
  /// 返回 [LineLexResult]，其中包含：
  /// - [tokens]：本行切分出的 [Token] 列表；
  /// - [outState]：本行结束时的状态（可能仍在字符串或多行注释中）。
  ///
  /// ### 处理能力
  /// - 单行注释：支持 `//` 与 `#`；
  /// - 多行注释：`/* ... */`，可跨行；
  /// - 字符串：支持 `'...'` 与 `"..."`，处理反斜杠转义；
  /// - 数字：支持整数、小数，允许字母/下划线作为后缀（如 `123f`, `0xFF`）；
  /// - 标识符：字母/数字/下划线/`$`；若命中 [keywords]，标记为关键字；
  /// - 操作符 / 标点：通过 [operators] / [punctuation] 集合匹配；
  /// - 空白：空格、Tab、`\r`。
  LineLexResult tokenizeLine(String line, LexState inState) {
    final tokens = <Token>[];

    int i = 0;
    LexState state = inState;

    /// 工具函数：向 token 列表添加一个 [start, end) 区间的 token。
    void push(int start, int end, TokenType t) {
      if (end > start) tokens.add(Token(start, end, t));
    }

    bool startsWithAt(String s, int idx) => line.startsWith(s, idx);

    while (i < line.length) {
      final ch = line[i];

      // ==============================
      // 处理“非 normal”状态
      // ==============================
      if (state == LexState.blockComment) {
        // 多行注释内，查找结束符 */
        final endIdx = line.indexOf('*/', i);
        if (endIdx == -1) {
          // 整行都是注释，保持 blockComment 状态
          push(i, line.length, TokenType.comment);
          i = line.length;
          state = LexState.blockComment;
          break;
        } else {
          push(i, endIdx + 2, TokenType.comment);
          i = endIdx + 2;
          state = LexState.normal;
          continue;
        }
      } else if (state == LexState.stringSingle) {
        // 单引号字符串，支持转义
        int j = i;
        while (j < line.length) {
          if (line[j] == '\\') {
            j += 2; // 跳过转义
            continue;
          }
          if (line[j] == '\'') {
            j++;
            state = LexState.normal;
            break;
          }
          j++;
        }
        push(i, j, TokenType.string);
        i = j;
        continue;
      } else if (state == LexState.stringDouble) {
        // 双引号字符串，支持转义
        int j = i;
        while (j < line.length) {
          if (line[j] == '\\') {
            j += 2;
            continue;
          }
          if (line[j] == '"') {
            j++;
            state = LexState.normal;
            break;
          }
          j++;
        }
        push(i, j, TokenType.string);
        i = j;
        continue;
      }

      // ==============================
      // normal 模式
      // ==============================

      // 空白
      if (isWhitespace(ch)) {
        final start = i;
        while (i < line.length && isWhitespace(line[i])) {
          i++;
        }
        push(start, i, TokenType.whitespace);
        continue;
      }

      // 单行注释
      if (startsWithAt('//', i)) {
        push(i, line.length, TokenType.comment);
        i = line.length;
        break;
      }
      if (line[i] == '#') {
        push(i, line.length, TokenType.comment);
        i = line.length;
        break;
      }

      // 多行注释开始
      if (startsWithAt('/*', i)) {
        final endIdx = line.indexOf('*/', i + 2);
        if (endIdx == -1) {
          // 本行未闭合
          push(i, line.length, TokenType.comment);
          i = line.length;
          state = LexState.blockComment;
          break;
        } else {
          push(i, endIdx + 2, TokenType.comment);
          i = endIdx + 2;
          continue;
        }
      }

      // 字符串开始
      if (ch == '\'') {
        state = LexState.stringSingle;
        push(i, i + 1, TokenType.string);
        i += 1;
        continue;
      }
      if (ch == '"') {
        state = LexState.stringDouble;
        push(i, i + 1, TokenType.string);
        i += 1;
        continue;
      }

      // 数字字面量
      if (isDigit(ch)) {
        final start = i;
        i++;
        while (i < line.length && (isDigit(line[i]) || line[i] == '.' || isAlpha(line[i]) || line[i] == '_')) {
          i++;
        }
        push(start, i, TokenType.number);
        continue;
      }

      // 标识符 / 关键字
      if (isAlpha(ch) || ch == '_' || ch == r'$') {
        final start = i;
        i++;
        while (i < line.length && (isAlphaNum(line[i]) || line[i] == '_' || line[i] == r'$')) {
          i++;
        }
        final lexeme = line.substring(start, i);
        final isKw = keywords.contains(lexeme);
        push(start, i, isKw ? TokenType.keyword : TokenType.identifier);
        continue;
      }

      // 操作符
      if (operators.contains(ch)) {
        push(i, i + 1, TokenType.operator_);
        i += 1;
        continue;
      }

      // 标点符号
      if (punctuation.contains(ch)) {
        push(i, i + 1, TokenType.punctuation);
        i += 1;
        continue;
      }

      // Fallback：未识别符号
      push(i, i + 1, TokenType.other);
      i += 1;
    }

    return LineLexResult(tokens, state);
  }

  // ==============================
  // 工具函数：字符分类
  // ==============================
  static bool isWhitespace(String c) => c == ' ' || c == '\t' || c == '\r';
  static bool isDigit(String c) => c.codeUnitAt(0) >= 48 && c.codeUnitAt(0) <= 57;
  static bool isAlpha(String c) {
    final u = c.codeUnitAt(0);
    return (u >= 65 && u <= 90) || (u >= 97 && u <= 122);
  }
  static bool isAlphaNum(String c) => isAlpha(c) || isDigit(c);

  /// 常见操作符字符集合。
  static const Set<String> operators = {
    '+','-','*','/','%','=','!','<','>','&','|','^','~',':','?'
  };

  /// 常见标点字符集合。
  static const Set<String> punctuation = {
    '(',')','[',']','{','}','.',',',';'
  };
}

/// 一行词法分析的结果。
///
/// - [tokens]：切分出的 token 列表；
/// - [outState]：行结束时的状态（若仍在多行注释/字符串中，则带出）。
class LineLexResult {
  final List<Token> tokens;
  final LexState outState;

  LineLexResult(this.tokens, this.outState);
}
